/**
 * hook-fetch 实例工厂
 * 用于创建不同配置的请求实例
 */

import type { HookFetchPlugin } from 'hook-fetch';
import hookFetch from 'hook-fetch';
import { ElMessage } from 'element-plus';
import router from '@/routers';
import type { 
  IHttpResponse, 
  IObject, 
  IHookFetchConfig,
  IInterceptorConfig 
} from './hookFetchTypes';

// 默认配置
const DEFAULT_CONFIG: IHookFetchConfig = {
  baseURL: import.meta.env.VITE_API_URL || '',
  timeout: 10000,
  headers: {
    'Content-Type': 'application/json;charset=UTF-8',
  },
  interceptors: {
    enableAuth: true,
    enableDeduplication: true,
    enableErrorHandler: true,
    tokenKey: 'token',
    authHeaderName: 'token',
  },
};

// 工具函数
const getToken = (): string | null => {
  return localStorage.getItem('token') || sessionStorage.getItem('token');
};

const getLocaleLang = (): string => {
  return localStorage.getItem('locale') || 'zh-CN';
};

const getValueByKeys = (obj: any, path: string, defaultValue: any = undefined): any => {
  const keys = path.split('.');
  let result = obj;
  for (const key of keys) {
    if (result && typeof result === 'object' && key in result) {
      result = result[key];
    } else {
      return defaultValue;
    }
  }
  return result;
};

// 请求去重管理
class RequestDeduplication {
  private pending: IObject<number> = {};

  getKey(config: any): string {
    const url = config.url || '';
    const params = new URLSearchParams(config.params as any).toString();
    return encodeURIComponent(url + (params ? '?' + params : ''));
  }

  add(key: string): boolean {
    if (this.pending[key]) {
      return false; // 已存在，拒绝请求
    }
    this.pending[key] = 1;
    return true;
  }

  remove(key: string): void {
    delete this.pending[key];
  }

  clear(): void {
    this.pending = {};
  }
}

// 创建请求拦截器
function createRequestInterceptor(config: IInterceptorConfig): HookFetchPlugin<IHttpResponse> {
  return {
    name: 'requestInterceptor',
    beforeRequest: async (requestConfig) => {
      requestConfig.headers = new Headers(requestConfig.headers);
      
      // 设置通用请求头
      requestConfig.headers.set('X-Requested-With', 'XMLHttpRequest');
      requestConfig.headers.set('Request-Start', new Date().getTime().toString());
      requestConfig.headers.set('Accept-Language', getLocaleLang());

      // 设置认证token
      if (config.enableAuth) {
        const token = getToken();
        if (token) {
          requestConfig.headers.set(config.authHeaderName || 'token', token);
        }
      }

      // GET请求添加时间戳防缓存
      if (requestConfig.method?.toUpperCase() === 'GET') {
        const url = new URL(requestConfig.url!, window.location.origin);
        url.searchParams.set('_t', new Date().getTime().toString());
        requestConfig.url = url.pathname + url.search;
      }

      // 处理表单数据
      if (requestConfig.headers.get('Content-Type')?.includes('application/x-www-form-urlencoded')) {
        if (requestConfig.body && typeof requestConfig.body === 'object') {
          const formData = new URLSearchParams();
          Object.entries(requestConfig.body as IObject).forEach(([key, value]) => {
            formData.append(key, String(value));
          });
          requestConfig.body = formData.toString();
        }
      }

      return requestConfig;
    },
  };
}

// 创建响应拦截器
function createResponseInterceptor(config: IInterceptorConfig): HookFetchPlugin<IHttpResponse> {
  return {
    name: 'responseInterceptor',
    afterResponse: async (response) => {
      // 处理401未授权
      if (response.result?.code === 401) {
        router.replace('/login');
        throw new Error('未授权，请登录');
      }

      return response;
    },
    onError: async (error) => {
      if (!config.enableErrorHandler) {
        throw error;
      }

      const status = getValueByKeys(error, 'response.status', 500);
      
      const httpCodeLabel: IObject<string> = {
        400: '请求参数错误',
        401: '未授权，请登录',
        403: '拒绝访问',
        404: `请求地址出错: ${getValueByKeys(error, 'response.url', '')}`,
        408: '请求超时',
        500: 'API接口报500错误',
        501: '服务未实现',
        502: '网关错误',
        503: '服务不可用',
        504: '网关超时',
        505: 'HTTP版本不受支持'
      };

      if (error && error.response) {
        console.error('请求错误', error.response);
      }

      if (status === 401) {
        router.replace('/login');
      }

      const errorMessage = httpCodeLabel[status] || '接口错误';
      ElMessage.error(errorMessage);
      
      throw new Error(errorMessage);
    },
  };
}

// 创建请求去重插件
function createDeduplicationPlugin(deduplication: RequestDeduplication): HookFetchPlugin<IHttpResponse> {
  return {
    name: 'requestDeduplication',
    beforeRequest: async (config) => {
      const key = deduplication.getKey(config);
      
      if (!deduplication.add(key)) {
        throw new Error('-999'); // 重复请求标识
      }

      return config;
    },
    afterResponse: async (response, config) => {
      const key = deduplication.getKey(config);
      deduplication.remove(key);
      return response;
    },
    onError: async (error, config) => {
      if (config) {
        const key = deduplication.getKey(config);
        deduplication.remove(key);
      }
      throw error;
    },
  };
}

/**
 * 创建hook-fetch实例
 * @param customConfig 自定义配置
 * @returns hook-fetch实例
 */
export function createHookFetchInstance(customConfig: Partial<IHookFetchConfig> = {}) {
  const config = { ...DEFAULT_CONFIG, ...customConfig };
  const deduplication = new RequestDeduplication();
  
  const plugins: HookFetchPlugin<IHttpResponse>[] = [];

  // 添加请求拦截器
  if (config.interceptors?.enableAuth || config.interceptors?.enableErrorHandler) {
    plugins.push(createRequestInterceptor(config.interceptors));
  }

  // 添加响应拦截器
  if (config.interceptors?.enableErrorHandler) {
    plugins.push(createResponseInterceptor(config.interceptors));
  }

  // 添加请求去重插件
  if (config.interceptors?.enableDeduplication) {
    plugins.push(createDeduplicationPlugin(deduplication));
  }

  const instance = hookFetch.create<IHttpResponse>({
    baseURL: config.baseURL,
    headers: config.headers,
    plugins,
  });

  return {
    instance,
    deduplication,
    // 便捷方法
    request: (requestConfig: any) => instance.request(requestConfig).then(response => response.result!),
    get: (url: string, params?: IObject, headers?: IObject) => 
      instance.get(url, { params, headers }).then(response => response.result!),
    post: (url: string, data?: any, headers?: IObject) => 
      instance.post(url, data, { headers }).then(response => response.result!),
    put: (url: string, data?: any, headers?: IObject) => 
      instance.put(url, data, { headers }).then(response => response.result!),
    delete: (url: string, data?: any, headers?: IObject) => 
      instance.delete(url, { body: data, headers }).then(response => response.result!),
  };
}

// 默认实例
export const defaultHookFetchInstance = createHookFetchInstance();

// 导出默认请求方法
export const { request, get, post, put, delete: del } = defaultHookFetchInstance;

export default defaultHookFetchInstance.request;